import React, { useRef, useEffect, memo, useState } from 'react'
import Controller from './controller'
import { useVideoCallback, useVideoListener, useListenBuffering, useShortCut, useEventListen } from '../utils'
import styles from './index.module.scss'
import { videoAutoPlay, errorVideo, removeVideo } from './utils'
import { useRecoilState, useSetRecoilState, useRecoilValue } from 'recoil'
import {
  videoRefs,
  videoProps,
  videoPlayEnded,
  videoFirstBuffering,
  videoBuffering,
  videoDuration,
  videoPlayStatus,
  videoScreenFull
} from '../store'
import { useRouter } from 'next/router'
import { userInfo, cacheLineState } from '@/store'
import { PLAY_ERR_CODE, useErrorCodeValue, useSetErrorCode } from '../error-center'
import { AUTO_KEY } from '@/constant'
import dynamic from 'next/dynamic'
import CustomLoader from './custom-loader/loader'
import { generateVodUrl, generatePlayUrl } from '@/utils/utils'
import { getVodHistoryDuration } from '@/api/history-collect'
import EventBus from '@/utils/emitter'

const NotLogin = dynamic(() => import('@c/not-login'))
const GetVipDom = dynamic(() => import('@c/get-vip-dom'))
const OnlyVipDom = dynamic(() => import('@c/only-vip-dom'))
const NoSourceDom = dynamic(() => import('@c/no-source-dom'))
const VodPlayError = dynamic(() => import('@c/vod-play-error'))
const JujiBox = dynamic(() => import('../components/juji-box'))
const ManualPlay = dynamic(() => import('../components/manual-play'))
const LiveJujiBox = dynamic(() => import('../components/live-juji-box'))
const PlayErrorMask = dynamic(() => import('../components/play-error-mask'))
const Loading = dynamic(() => import('../components/loading'))
const BufferComponent = dynamic(() => import('../components/buffering'))

let playIndex = 0 //直播播放切换指针

//检测当前线路是否是最后一条播放线路了
const isLastPlayLine = (lineState, lineArr) => {
  const lineIndex = lineArr.findIndex(item => item.lId === lineState.lId)
  const lastObj = {
    index: lineIndex + 1
  }
  if (lineIndex === lineArr.length - 1) {
    lastObj.isEnd = true
  } else {
    lastObj.isEnd = false
  }
  return lastObj
}

// 切换线路源逻辑处理
const switchPlayLine = ({
  router,
  lineState,
  updateLineState,
  onLineSwitch,
  lineArr,
  onError,
  updatePlayUrl,
  user
}) => {
  const { pathname } = router
  // 官方线失败但是有普通线
  if (pathname === '/vod/play-official/[id]/[ep]') {
    const lastObj = isLastPlayLine(lineState, lineArr)
    if (!lastObj.isEnd) {
      //非会员切换普通线路，上一个普通线路播放失败时回调
      if (!user.isVip && !lineState.isOfficial) {
        onLineSwitch?.({
          type: 'not-vip',
          content: '线路起播失败，正在起播新线路'
        })
      } else if (user.isVip) {
        onLineSwitch?.({
          content: '线路起播失败，正在起播新线路',
          type: 'vip'
        })
      }
      updateLineState({ ...lineArr[lastObj.index] })
    } else {
      // 官方线路失败且没有普通线。
      onError?.()
    }
    return
  } else if (pathname === '/live/[id]') {
    if (lineArr.length < playIndex + 1) {
      onError?.()
    } else {
      const url = lineArr[playIndex].url
      updatePlayUrl(generatePlayUrl(url, AUTO_KEY))
      playIndex++
    }
  } else {
    onError?.()
  }
}

/**
 * playType HLS|MP4
 * hideNext
 * hideProgress
 * hideSpeed
 * */

const playError = ['networkError']
const ReactVideo = props => {
  const {
    keywords,
    description,
    style,
    hlsConfig,
    playType,
    onError,
    isLive,
    useCustomLoader = false,
    needP2P = false,
    lineArr,
    cid,
    ep,
    from,
    isInit,
    lineStatus,
    name,
    isMovie,
    onNormalStart,
    currPlayLines,
    lineGroup,
    selectionInfo,
    isShows,
    totalSize,
    onLineSwitch //普通线路切换回调
  } = props
  const [lineState, updateLineState] = useRecoilState(cacheLineState)
  const setVideoEnd = useSetRecoilState(videoPlayEnded)
  const router = useRouter()
  const user = useRecoilValue(userInfo)
  const setVideoRefs = useSetRecoilState(videoRefs)
  const setVideoProps = useSetRecoilState(videoProps)
  const [isFirstBuffering, setVideoFirstBuffering] = useRecoilState(videoFirstBuffering)
  const duration = useRecoilValue(videoDuration)
  const [isBuffering, setVideoBuffering] = useRecoilState(videoBuffering)
  const errorCode = useErrorCodeValue()
  const setErrorCode = useSetErrorCode()
  const [autoplayError, setAutoplayError] = useState(false) //自动播放失败
  const errorCircleTimer = useRef(null) //播放错误轮询
  const handleErrorTimer = useRef(null) //播放错误执行回调timer,在合适的时机会销毁定时器
  const videoRef = useRef(null) // 视频对象
  const videoContainerRef = useRef(null) // 视频容器对象
  const [openJuji, setOpenJuji] = useState(false) //点播的
  const [switchLineTag, toggleSwitchLineTag] = useState(false) //切换播放线路标识。用来做切线处理。
  const isPlay = useRecoilValue(videoPlayStatus)
  const [playUrl, updatePlayUrl] = useState('')
  const [isEndEd, setEnded] = useRecoilState(videoPlayEnded)
  const isFullScreen = useRecoilValue(videoScreenFull)
  const getPlayLineUrl = (lineArr, lineObj) => {
    const { index = 0, lId } = lineObj || {}
    const lIdUrl = lineArr.find(item => item.lId === lId)
    if (lIdUrl) {
      return lIdUrl
    }
    try {
      const line = lineArr[index]
      return line
    } catch (error) {
      // 上述两种方式都拿不到则直接拿第一个
      return lineArr?.length ? lineArr[0] : ''
    }
  }

  //点播更新播放url
  useEffect(() => {
    if (from !== 'VOD' || !isInit) {
      return
    }
    const currLine = getPlayLineUrl(lineArr, lineState)
    let url = currLine?.purl
    url?.replace('http://', 'https://')
    // 点播官方线路处理
    if (currLine?.isOfficial) {
      url = generateVodUrl(currLine?.purl, AUTO_KEY)
    }
    updatePlayUrl(url)
  }, [lineArr, lineState, router.asPath, isInit])

  // 直播更新播放url
  useEffect(() => {
    if (from !== 'LIVE') {
      return
    }
    playIndex = 0
    try {
      let url = lineArr[playIndex].url
      url = generatePlayUrl(url, AUTO_KEY)
      updatePlayUrl(url)
    } catch (error) {}
  }, [lineArr, router.asPath])

  // 体育更新播放url
  useEffect(() => {
    if (from !== 'SPORT') {
      return
    }
    updatePlayUrl(lineArr[0])
  }, [lineArr, router.asPath])

  // 体育直播
  useEffect(() => {
    if (from !== 'SPORT_LIVE') {
      return
    }
    try {
      let url = lineArr[0]
      url = generatePlayUrl(url, AUTO_KEY)
      updatePlayUrl(url)
    } catch (error) {}
  }, [lineArr, router.asPath])

  // 自建更新url
  useEffect(() => {
    if (from !== 'CUSTOM') {
      return
    }
    updatePlayUrl(lineArr[0])
  }, [lineArr, router.asPath])

  const toggleJuji = () => {
    setOpenJuji(!openJuji)
  }
  const clearTimer = () => {
    if (errorCircleTimer.current) {
      clearTimeout(errorCircleTimer.current)
      errorCircleTimer.current = null
    }
  }
  const clearHandleTimer = () => {
    if (handleErrorTimer.current) {
      toggleSwitchLineTag(false)
      clearTimeout(handleErrorTimer.current)
      handleErrorTimer.current = null
    }
  }
  //添加video事件监听
  useVideoListener(videoRef.current)
  // 缓冲加载监听
  useListenBuffering(videoRef.current)
  // 快捷事件监听
  useShortCut(videoRef.current)
  // 回调监听
  useVideoCallback()
  // EventBus事件监听
  useEventListen(videoRef.current)
  // hls初始化
  const setHls = async () => {
    errorVideo()
    // p2p配置
    var p2pConfig = {
      strictSegmentId: true,
      live: isLive,
      trackerZone: 'hk',
      token: 'lQG_q-BIg'
    }
    const videoElement = videoRef.current
    const Hls = require('hls.js')
    if (Hls.isSupported()) {
      const config = { ...hlsConfig }
      if (useCustomLoader) {
        config.loader = CustomLoader
      }
      window.varHls = new Hls(config)
      if (needP2P && (lineState.isOfficial || isLive)) {
        const P2pEngineHls = (await import('swarmcloud-hls')).default // 动态导入
        if (P2pEngineHls.isSupported()) {
          p2pConfig.hlsjsInstance = window.varHls
          new P2pEngineHls(p2pConfig)
        }
      }
      window.varHls?.loadSource(playUrl)
      window.varHls?.attachMedia(videoElement)
      window.varHls?.on(Hls.Events.ERROR, (_, error) => {
        // 链接403的时候进行处理
        if (error?.loader?.loader?.status >= 400 || playError.includes(error.type) || !playUrl.includes('.m3u8')) {
          clearTimer()
          clearHandleTimer()
          handleErrorTimer.current = setTimeout(() => {
            toggleSwitchLineTag(true)
          }, 5000)
          return
        }
      })
      // 下一片段加载成功，则销毁上一片段加载错误的定时器
      window.varHls?.on(Hls.Events.FRAG_LOADING, function () {
        clearHandleTimer()
      })
      window.varHls?.on(Hls.Events.FRAG_LOADED, function () {
        clearHandleTimer()
      })

      window.varHls?.on(Hls.Events.MANIFEST_PARSED, function () {
        clearHandleTimer()
        clearTimer()
        // 自动播放
        videoAutoPlay(videoRef)
        if (!lineState.isOfficial) {
          onNormalStart()
        }
      })
    } else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
      videoElement.src = playUrl
      videoAutoPlay(videoRef, setAutoplayError)
      if (!lineState.isOfficial) {
        onNormalStart()
      }
      if (needP2P && (lineState.isOfficial || isLive)) {
        const P2pEngineHls = (await import('swarmcloud-hls')).default //动态导入
        P2pEngineHls.tryRegisterServiceWorker(p2pConfig)
      }
    }
  }

  // flv初始化
  const setFlv = async () => {
    const mpegts = (await import('mpegts.js')).default
    if (mpegts.getFeatureList().mseLivePlayback) {
      window.varFlvPlayer = mpegts.createPlayer({
        type: 'mse',
        isLive: true,
        url: '/api/loadflv?url=' + playUrl.replace('?','&')
      })
      window.varFlvPlayer.attachMediaElement(videoRef.current)
      window.varFlvPlayer.load()
      // 自动播放
      videoAutoPlay(videoRef)
    }
  }

  // 去除video的操作栏
  const banControls = () => {
    videoRef.current.controls = false
    videoRef.current.removeAttribute('controls')
  }

  // 初始加载资源，errorCode改变，设置video的数据
  useEffect(() => {
    if (!videoRef.current || !playUrl || errorCode) {
      setVideoBuffering(false)
      setVideoFirstBuffering(false)
      errorVideo()
      return
    }
    setEnded(false)
    setVideoFirstBuffering(true)
    setVideoBuffering(false)
    banControls()
    if (playType === 'FLV') {
      setFlv()
    } else if (playType !== 'MP4') {
      setHls()
    } else {
      videoRef.current.src = playUrl
      // 自动播放
      videoAutoPlay(videoRef)
    }
    clearTimer()
    clearHandleTimer()
  }, [playUrl, videoRef, errorCode])

  // 设置播放进度。
  useEffect(() => {
    if (from !== 'VOD') {
      return
    }
    videoRef.current.currentTime = 0
    if (!duration) {
      return
    }
    const token = localStorage.getItem('token')
    //已登录用接口数据
    if (token) {
      getVodHistoryDuration({ cid }, token).then(res => {
        if (ep == res.data?.num) {
          videoRef.current.currentTime = res.data?.playProgress || 0
        }
      })
      //未登录用缓存数据
    } else {
      let vodHistory = JSON.parse(localStorage.getItem('vod-history') || '[]')
      const playedLine = vodHistory.find(item => item.cid == cid && item.num == ep)
      if (playedLine) {
        videoRef.current.currentTime = playedLine.playProgress
      }
    }
  }, [playUrl, duration, lineState])

  // 每次在切换剧集的时候，恢复playIndex的值。
  useEffect(() => {
    playIndex = 0
    setErrorCode(0)
  }, [router.asPath])

  // 设置video ref
  useEffect(() => {
    setVideoRefs({
      videoRef: videoRef.current,
      videoContainerRef: videoContainerRef.current
    })
  }, [videoRef.current])

  // 设置 video props
  useEffect(() => {
    setVideoProps(props)
  }, [props])

  // 添加点击事件，用在剧集关闭
  useEffect(() => {
    const click = () => setOpenJuji(false)
    window.addEventListener('click', click)
    playIndex = 0
    return () => {
      // 移除播放器以及依赖
      removeVideo()
      window.removeEventListener('click', click)
      clearTimer()
    }
  }, [])

  // 点播监听播放结束
  useEffect(() => {
    EventBus.on('vod_end', () => {
      const isEnd = ep >= totalSize
      setVideoEnd(isEnd)
      if (!isEnd) {
        router.replace(`/vod/play-official/${cid}/${+ep + 1}`)
      }
    })
    return () => {
      EventBus.offAll('vod_end')
    }
  }, [cid, ep])

  // 手动播放
  const autoPlay = () => {
    setAutoplayError(false)
    videoRef.current.play()
  }

  // 切换播放线路。
  useEffect(() => {
    if (!switchLineTag) {
      return
    }
    toggleSwitchLineTag(false)

    switchPlayLine({ router, lineState, updateLineState, onLineSwitch, lineArr, updatePlayUrl, playUrl, onError, user })
  }, [switchLineTag])

  return (
    <div className={styles['player-container']} ref={videoContainerRef} style={style}>
      <video
        id="histar-player"
        className={styles['player']}
        ref={videoRef}
        description={description}
        keywords={keywords}
        src={playUrl}
        webkit-playsinline=""
        playsInline=""
        x5-video-player-type="h5"
        controlsList="nodownload"
      ></video>
      {errorCode == '7' && (
        <NotLogin
          className={styles.notLogin}
          isMovie={isMovie}
          name={name}
          lineStatus={lineStatus}
          lineArr={lineArr}
          isLive={isLive}
          clearErrorCode={() => setErrorCode(0)}
          ep={ep}
        />
      )}
      {/* 首次缓冲加载DOM */}
      {isFirstBuffering && !errorCode && !autoplayError && <BufferComponent className={styles['player-loading']} />}

      {/* 资源缓冲动画 */}
      {isBuffering && !isFirstBuffering && !errorCode && !autoplayError && (
        <Loading className={styles['player-loading']} />
      )}

      {/* controls操作栏&暂停播放DOM */}
      <Controller toggleJuji={toggleJuji} openJuji={openJuji} closeJuji={() => setOpenJuji(false)} />

      {/* 播放暂停按钮 */}
      {!isBuffering && !errorCode && !isFirstBuffering && !isPlay && !isEndEd && (
        <img
          alt="暂停"
          onClick={() => videoRef.current.play()}
          className={styles.playPause}
          src="/images/video/play-pause.webp"
        />
      )}

      {/* 非VIP|未登录|求片打底图 */}
      {errorCode ? isFirstBuffering || isBuffering ? null : <PlayErrorMask type={PLAY_ERR_CODE[errorCode]} /> : null}

      {/* 无数据求片 */}
      {errorCode == '4' ? <NoSourceDom data={[]} /> : null}

      {/* 有最优有普通，非VIP提示 */}
      {errorCode == '1-1' || errorCode == '5' ? (
        <GetVipDom lineArr={lineArr} clearErrorCode={() => setErrorCode(0)} isLive={isLive} />
      ) : null}
      {/* 只有最优非vip提示 */}
      {errorCode == '2-1' ? <OnlyVipDom /> : null}
      {/* 剧集信息 */}
      {openJuji && !isLive && isFullScreen ? (
        <JujiBox
          isShows={isShows}
          currPlayLines={currPlayLines}
          isMovie={isMovie}
          selectionInfo={selectionInfo}
          lineGroup={lineGroup}
          setErrorCode={setErrorCode}
          onClose={() => setOpenJuji(false)}
        />
      ) : null}

      {/* 直播剧集信息 */}
      {openJuji && isLive && isFullScreen ? <LiveJujiBox data={props.channels || {}} /> : null}

      {/* vip加载失败 */}
      {errorCode === '3' ? <VodPlayError lineArr={lineArr} clearErrorCode={() => setErrorCode(0)} /> : null}

      {/* 非播放失败浮层 */}
      {autoplayError ? <ManualPlay autoPlay={autoPlay} /> : null}
    </div>
  )
}

export default memo(ReactVideo)
